⚠️ 本文僅供防禦性研究與教育用途。 請只在你擁有或經授權的網路環境中執行。在未授權網路上監聽流量在多數國家屬於違法行為。
如果你的廠區有用 Modbus TCP — 統計上,很可能就是有 — 那麼每一次 register 讀取、每一次 coil 寫入、每一個感測器數值,都正在你的網路上以明文飛來飛去。沒有加密、沒有認證、沒有簽章,什麼都沒有。
Modbus 是 1979 年由 Modicon 設計的,當時的應用情境是:一台 PLC 透過一條獨立的串列線,跟現場幾個設備講話。那年代的威脅模型是「會不會有人實體接上這條線」。解法是「不要讓陌生人進控制室」就好。
45 年後,同一個協定跑在你的企業 VLAN 上,連著雲端 historian,而且 — 如果你的 IT/OT 網路分隔有破口 — 可能還可以從網際網路觸及。
讓我直接讓你看,從網路線的角度看,這長什麼樣子。
這是一個防禦性監控工具。你的團隊也會用同樣的程式碼來建立流量基準、偵測異常。需要安裝 scapy:
pip install scapy
from scapy.all import sniff, TCP, Raw
def show_modbus(pkt):
if TCP in pkt and pkt[TCP].dport == 502 and Raw in pkt:
payload = pkt[Raw].load
print(f"{pkt['IP'].src} → {pkt['IP'].dst}: {payload.hex()}")
sniff(filter="tcp port 502", prn=show_modbus, store=False)
把它跑在 span port、TAP、或 mirror VLAN 上,幾秒之內你就會看到類似這樣的東西:
192.168.1.50 → 192.168.1.10: 0001000000060103006400 02
192.168.1.10 → 192.168.1.50: 00010000000701030441f00000
192.168.1.50 → 192.168.1.10: 00020000000601100065000102
每一個 byte 都在訴說一個故事。我們來解碼第一個封包。
Modbus TCP 的封包格式在規範裡有完整文件 — 規範是公開的,這本身就是問題的一部分:
Bytes 0-1: Transaction ID(交易序號)
Bytes 2-3: Protocol ID(永遠是 0x0000)
Bytes 4-5: 後續長度
Byte 6: Unit ID(slave 位址)
Byte 7: Function code(功能碼)
Byte 8+: 功能碼對應的資料
所以 0001000000060103006400 02 解出來是:
| Bytes | 值 | 意義 |
|---|---|---|
0001 |
TID 1 | 序號 |
0000 |
0 | Modbus 協定標記 |
0006 |
6 | 後續 6 bytes |
01 |
Unit 1 | Slave 位址 |
03 |
FC 03 | 讀取 Holding Register |
0064 |
100 | 從 register 100 開始 |
0002 |
2 | 讀 2 個 register |
對方的回應 (00010000000701030441f00000) 帶回 4 bytes 的資料:41f00000。用 big-endian float32 解,等於 30.0 — 看起來是溫度讀值。
你現在已經知道: .10 這台控制器,每秒從 .50 讀一次溫度。沒有帳密、沒有挑戰應答、沒有稽核紀錄。
被動監控 10 分鐘,通常足以還原出:
網路拓樸 — 每一台 PLC、HMI、SCADA polling client 的 IP 位址。
設備對應 — 哪些 Unit ID 存在、每個裝置回應哪些 function code、哪些 slave 從不回應(可能是過期文件殘留)。
Register 用途 — 觀察讀寫模式,你可以推測哪些 register 是設定值、哪些是製程值、哪些控制關鍵輸出。對照公開的 PLC 文件,你就把這個廠 reverse engineering 出來了。
生產數據 — 實際的溫度、壓力、流量、馬達轉速。如果你是競爭對手,這就是你要的 KPI 報告。如果你是國家級行為者,這就是目標標定資料。
作息模式 — 夜班幾點開始?設定值什麼時候改?保養什麼時候做?Modbus 流量都能回答。
以上沒有一項需要高深的工具。上面那段監控器是 5 行。
我不會給攻擊腳本。但你應該理解攻擊面,才能防禦它:
現實對照:2016 年烏克蘭電網攻擊使用了名為 Industroyer(又稱 CrashOverride)的惡意程式,它原生支援工業協定 — IEC 60870-5-101/104 和 IEC 61850 — 直接對變電站設備發送合法格式的指令,完全繞過 HMI 層。沒有 zero-day,沒有奇特的漏洞利用。只是不該被攻擊者觸及的網路上,出現了協定層級的存取。
三層,依影響度排序:
1. 網路分隔(這是唯一真正重要的事)
如果你的 Modbus 流量可以從辦公室 VLAN、訪客 WiFi、或 — 拜託不要 — 網際網路觸及,後面其他事都不用做了。ISA/IEC 62443 的 zones and conduits、確實落實的防火牆、jump host,這套完整跑過。
Shodan 目前顯示數萬台從網際網路可觸及的 Modbus 裝置。不要在這份名單上。
2. Modbus/TCP Security(Modbus Organization,2018)
如果無法做到完全 air-gap(大多數廠不行),就加密。Modbus/TCP Security 是 modbus.org 發布的規範,用 TLS 包裹 Modbus 並加上 X.509v3 憑證認證,使用 port 802,越來越多新一代控制器開始支援。遷移工程不小,但可行。
3. 被動監控 + 異常偵測
這就是上面那段監控程式真正派上用場的地方 — 用於防禦。建立你的正常流量基準:哪些 client 跟哪些 slave 講話、出現哪些 function code、碰到哪些 register 範圍、頻率如何。任何偏離基準的就告警。
你不需要昂貴的 ICS IDS 來開始。你需要 50 行 Python,加上定期看 log 的紀律。
我在做 100MW+ 規模的自動化專案,「我這個 Modbus 網路現在到底有什麼東西在跑」這個問題常常出現,所以我把監控工具包裝成產品:Modbus Logger Pro。它能自動偵測 50+ 種 PLC 的 byte order、記錄結構化流量,從防禦角度處理本文提出的問題。
但老實說 — 上面那 5 行就夠你開始了。這禮拜就在你自己的網路上跑一次。你會被你看到的東西嚇到。
如果這篇有共鳴,我接下來會繼續寫這方向 — 下篇 MQTT broker 暴露問題、再來是 OPC UA 意外完整的資安設計、然後是給電動車圈的 CAN bus 篇。對這領域有興趣可以追蹤。
延伸閱讀: